#include <gtest/gtest.h>
#include "viml/vm.h"
#include "viml/compiler.h"
#include "viml/lexer.h"
#include "viml/parser.h"
#include "viml/value.h"

using namespace viml;

class SpecialConstantsTest : public ::testing::Test {
protected:
    VM vm;
    Compiler compiler;
    
    Value execute_source(const std::string& source) {
        auto bytecode = compiler.compile(source);
        return vm.execute(bytecode);
    }
};

// 测试特殊常量的基本功能
TEST_F(SpecialConstantsTest, SpecialConstantsBasic) {
    // 测试 v:true
    {
        std::string source = "echo v:true";
        auto result = execute_source(source);
        // v:true 应该输出 1
    }
    
    // 测试 v:false
    {
        std::string source = "echo v:false";
        auto result = execute_source(source);
        // v:false 应该输出 0
    }
    
    // 测试 v:null
    {
        std::string source = "echo v:null"; 
        auto result = execute_source(source);
        // v:null 应该输出空字符串
    }
    
    // 测试 v:none
    {
        std::string source = "echo v:none";
        auto result = execute_source(source);
        // v:none 应该输出空字符串
    }
}

// 测试类型常量
TEST_F(SpecialConstantsTest, TypeConstants) {
    // 测试所有类型常量
    {
        std::string source = "echo v:t_number";
        auto result = execute_source(source);
        // 应该输出 0
    }
    
    {
        std::string source = "echo v:t_string";
        auto result = execute_source(source);
        // 应该输出 1
    }
    
    {
        std::string source = "echo v:t_function";
        auto result = execute_source(source);
        // 应该输出 2
    }
    
    {
        std::string source = "echo v:t_list";
        auto result = execute_source(source);
        // 应该输出 3
    }
    
    {
        std::string source = "echo v:t_dict";
        auto result = execute_source(source);
        // 应该输出 4
    }
    
    {
        std::string source = "echo v:t_float";
        auto result = execute_source(source);
        // 应该输出 5
    }
    
    {
        std::string source = "echo v:t_bool";
        auto result = execute_source(source);
        // 应该输出 6
    }
}

// 测试type()函数
TEST_F(SpecialConstantsTest, TypeFunction) {
    // 测试数字类型
    {
        std::string source = "echo type(42)";
        auto result = execute_source(source);
        // 应该输出 0 (v:t_number)
    }
    
    // 测试浮点数类型
    {
        std::string source = "echo type(3.14)";
        auto result = execute_source(source);
        // 应该输出 5 (v:t_float)
    }
    
    // 测试字符串类型
    {
        std::string source = "echo type(\"hello\")";
        auto result = execute_source(source);
        // 应该输出 1 (v:t_string)
    }
    
    // 测试布尔类型
    {
        std::string source = "echo type(v:true)";
        auto result = execute_source(source);
        // 应该输出 6 (v:t_bool)
    }
    
    {
        std::string source = "echo type(v:false)";
        auto result = execute_source(source);
        // 应该输出 6 (v:t_bool)
    }
    
    // 测试列表类型
    {
        std::string source = "echo type([1, 2, 3])";
        auto result = execute_source(source);
        // 应该输出 3 (v:t_list)
    }
    
    // 测试字典类型
    {
        std::string source = "echo type({\"a\": 1})";
        auto result = execute_source(source);
        // 应该输出 4 (v:t_dict)
    }
    
    // 测试特殊值类型
    {
        std::string source = "echo type(v:null)";
        auto result = execute_source(source);
        // 应该输出 0 (v:t_number，特殊：null被视为数字0)
    }
    
    {
        std::string source = "echo type(v:none)";
        auto result = execute_source(source);
        // 应该输出 0 (v:t_number，特殊：none被视为数字0)
    }
}

// 测试type()函数与类型常量的一致性
TEST_F(SpecialConstantsTest, TypeFunctionConsistency) {
    // 测试type()函数返回值与类型常量一致
    {
        std::string source = R"(
            let num = 42
            let num_type = type(num)
            let expected = v:t_number
            echo num_type
            echo expected
        )";
        auto result = execute_source(source);
        // 应该输出两个0
    }
    
    {
        std::string source = R"(
            let str = "hello"
            let str_type = type(str)
            let expected = v:t_string
            echo str_type
            echo expected
        )";
        auto result = execute_source(source);
        // 应该输出两个1
    }
}

// 测试特殊常量在表达式中的使用
TEST_F(SpecialConstantsTest, SpecialConstantsInExpressions) {
    // 测试布尔常量在条件表达式中
    {
        std::string source = R"(
            if v:true
                echo "true branch"
            endif
        )";
        auto result = execute_source(source);
        // 应该输出 "true branch"
    }
    
    {
        std::string source = R"(
            if v:false
                echo "false branch"
            else
                echo "else branch"
            endif
        )";
        auto result = execute_source(source);
        // 应该输出 "else branch"
    }
}

// 测试词法分析器对特殊常量的识别
TEST_F(SpecialConstantsTest, LexerSpecialConstants) {
    Lexer lexer("v:true v:false v:null v:none v:t_number");
    auto tokens = lexer.tokenize();
    
    // 应该有5个SPECIAL_CONSTANT token和1个EOF token
    ASSERT_EQ(tokens.size(), 6);
    
    EXPECT_EQ(tokens[0].type, TokenType::SPECIAL_CONSTANT);
    EXPECT_EQ(tokens[0].value, "v:true");
    
    EXPECT_EQ(tokens[1].type, TokenType::SPECIAL_CONSTANT);
    EXPECT_EQ(tokens[1].value, "v:false");
    
    EXPECT_EQ(tokens[2].type, TokenType::SPECIAL_CONSTANT);
    EXPECT_EQ(tokens[2].value, "v:null");
    
    EXPECT_EQ(tokens[3].type, TokenType::SPECIAL_CONSTANT);
    EXPECT_EQ(tokens[3].value, "v:none");
    
    EXPECT_EQ(tokens[4].type, TokenType::SPECIAL_CONSTANT);
    EXPECT_EQ(tokens[4].value, "v:t_number");
    
    EXPECT_EQ(tokens[5].type, TokenType::END_OF_FILE);
}

// 测试type()函数的错误处理
TEST_F(SpecialConstantsTest, TypeFunctionErrorHandling) {
    // 测试参数过多
    try {
        std::string source = "echo type(1, 2)";
        auto result = execute_source(source);
        FAIL() << "应该抛出异常";
    } catch (const std::exception& e) {
        // 预期的异常
        SUCCEED();
    }
    
    // 测试没有参数
    try {
        std::string source = "echo type()";
        auto result = execute_source(source);
        FAIL() << "应该抛出异常";
    } catch (const std::exception& e) {
        // 预期的异常
        SUCCEED();
    }
}